package dsl

import ast.expr.SqlBinaryOperator
import ast.expr.SqlExpr
import ast.expr.SqlSubQueryPredicate
import ast.order.SqlOrderByOption
import query.select.SelectQuery

/**
 * 查询dsl使用的表达式父类
 * @property alias String? 查询别名
 */
sealed class Query(open var alias: String?) {
    constructor() : this(null)

    /**
     * 用于生成Query + Query的二元表达式
     * 例如：column("c1") + column("c2") 或 column("c1").plus(column("c2"))
     * @param query Query 右侧表达式
     * @return QueryBinary 二元表达式
     */
    operator fun plus(query: Query): QueryBinary {
        return QueryBinary(this, SqlBinaryOperator.ADD, query)
    }

    /**
     * 用于生成Query + 常量的二元表达式
     * 例如：column("c1") + 1 或 column("c1").plus(1)
     * @param value T 右侧常量，右侧合法的类型有Number、String、Date、List、Boolean以及null
     * @return QueryBinary 二元表达式
     */
    operator fun <T> plus(value: T): QueryBinary {
        return QueryBinary(this, SqlBinaryOperator.ADD, const(value))
    }

    /**
     * 用于生成Query - Query的二元表达式
     * 例如：column("c1") - column("c2") 或 column("c1").minus(column("c2"))
     * @param query Query 右侧表达式
     * @return QueryBinary 二元表达式
     */
    operator fun minus(query: Query): QueryBinary {
        return QueryBinary(this, SqlBinaryOperator.SUB, query)
    }

    /**
     * 用于生成Query - 常量的二元表达式
     * 例如：column("c1") - 1  或 column("c1").minus(1)
     * @param value T 右侧常量，右侧合法的类型有Number、String、Date、List、Boolean以及null
     * @return QueryBinary 二元表达式
     */
    operator fun <T> minus(value: T): QueryBinary {
        return QueryBinary(this, SqlBinaryOperator.SUB, const(value))
    }

    /**
     * 用于生成Query * Query的二元表达式
     * 例如：column("c1") * column("c2") 或 column("c1").times(column("c2"))
     * @param query Query 右侧表达式
     * @return QueryBinary 二元表达式
     */
    operator fun times(query: Query): QueryBinary {
        return QueryBinary(this, SqlBinaryOperator.MUL, query)
    }

    /**
     * 用于生成Query * 常量的二元表达式
     * 例如：column("c1") * 1  或 column("c1").times(1)
     * @param value T 右侧常量，右侧合法的类型有Number、String、Date、List、Boolean以及null
     * @return QueryBinary 二元表达式
     */
    operator fun <T> times(value: T): QueryBinary {
        return QueryBinary(this, SqlBinaryOperator.MUL, const(value))
    }

    /**
     * 用于生成Query / Query的二元表达式
     * 例如：column("c1") / column("c2") 或 column("c1").div(column("c2"))
     * @param query Query 右侧表达式
     * @return QueryBinary 二元表达式
     */
    operator fun div(query: Query): QueryBinary {
        return QueryBinary(this, SqlBinaryOperator.DIV, query)
    }

    /**
     * 用于生成Query / 常量的二元表达式
     * 例如：column("c1") / 1  或 column("c1").div(1)
     * @param value T 右侧常量，右侧合法的类型有Number、String、Date、List、Boolean以及null
     * @return QueryBinary 二元表达式
     */
    operator fun <T> div(value: T): QueryBinary {
        return QueryBinary(this, SqlBinaryOperator.DIV, const(value))
    }

    /**
     * 用于生成Query % Query的二元表达式
     * 例如：column("c1") % column("c2") 或 column("c1").rem(column("c2"))
     * @param query Query 右侧表达式
     * @return QueryBinary 二元表达式
     */
    operator fun rem(query: Query): QueryBinary {
        return QueryBinary(this, SqlBinaryOperator.MOD, query)
    }

    /**
     * 用于生成Query % 常量的二元表达式
     * 例如：column("c1") % 1  或 column("c1").rem(1)
     * @param value T 右侧常量，右侧合法的类型有Number、String、Date、List、Boolean以及null
     * @return QueryBinary 二元表达式
     */
    operator fun <T> rem(value: T): QueryBinary {
        return QueryBinary(this, SqlBinaryOperator.MOD, const(value))
    }

    /**
     * 用于生成Query = Query的二元表达式
     * 例如：column("c1") eq column("c2") 或 column("c1").eq(column("c2"))
     * @param query Query 右侧表达式
     * @return QueryBinary 二元表达式
     */
    infix fun eq(query: Query): QueryBinary {
        return QueryBinary(this, SqlBinaryOperator.EQ, query)
    }

    /**
     * 用于生成Query = 常量的二元表达式
     * 例如：column("c1") eq 1  或 column("c1").eq(1)
     * @param query T 右侧常量，右侧合法的类型有Number、String、Date、List、Boolean以及null
     * @return QueryBinary 二元表达式
     */
    infix fun <T> eq(query: T): QueryBinary {
        return QueryBinary(this, SqlBinaryOperator.EQ, const(query))
    }

    /**
     * 用于生成Query = 子查询的二元表达式
     * 例如：column("c1") eq (Select() from Table) 或 column("c1").eq(Select() from Table)
     * @param query SelectQuery 子查询
     * @return QueryBinary 二元表达式
     */
    infix fun eq(query: SelectQuery): QueryBinary {
        return QueryBinary(this, SqlBinaryOperator.EQ, QuerySub(query))
    }

    /**
     * 用于生成Query <> Query的二元表达式
     * 例如：column("c1") ne column("c2") 或 column("c1").ne(column("c2"))
     * @param query Query 右侧表达式
     * @return QueryBinary 二元表达式
     */
    infix fun ne(query: Query): QueryBinary {
        return QueryBinary(this, SqlBinaryOperator.NE, query)
    }

    /**
     * 用于生成Query <> 常量的二元表达式
     * 例如：column("c1") ne 1  或 column("c1").ne(1)
     * @param query T 右侧常量，右侧合法的类型有Number、String、Date、List、Boolean以及null
     * @return QueryBinary 二元表达式
     */
    infix fun <T> ne(query: T): QueryBinary {
        return QueryBinary(this, SqlBinaryOperator.NE, const(query))
    }

    /**
     * 用于生成Query <> 子查询的二元表达式
     * 例如：column("c1") ne (Select() from Table) 或 column("c1").ne(Select() from Table)
     * @param query SelectQuery 子查询
     * @return QueryBinary 二元表达式
     */
    infix fun ne(query: SelectQuery): QueryBinary {
        return QueryBinary(this, SqlBinaryOperator.NE, QuerySub(query))
    }

    /**
     * 用于生成Query > Query的二元表达式
     * 例如：column("c1") gt column("c2") 或 column("c1").gt(column("c2"))
     * @param query Query 右侧表达式
     * @return QueryBinary 二元表达式
     */
    infix fun gt(query: Query): QueryBinary {
        return QueryBinary(this, SqlBinaryOperator.GT, query)
    }

    /**
     * 用于生成Query > 常量的二元表达式
     * 例如：column("c1") gt 1  或 column("c1").gt(1)
     * @param query T 右侧常量，右侧合法的类型有Number、String、Date、List、Boolean以及null
     * @return QueryBinary 二元表达式
     */
    infix fun <T> gt(query: T): QueryBinary {
        return QueryBinary(this, SqlBinaryOperator.GT, const(query))
    }

    /**
     * 用于生成Query > 子查询的二元表达式
     * 例如：column("c1") gt (Select() from Table) 或 column("c1").gt(Select() from Table)
     * @param query SelectQuery 子查询
     * @return QueryBinary 二元表达式
     */
    infix fun gt(query: SelectQuery): QueryBinary {
        return QueryBinary(this, SqlBinaryOperator.GT, QuerySub(query))
    }

    /**
     * 用于生成Query >= Query的二元表达式
     * 例如：column("c1") ge column("c2") 或 column("c1").ge(column("c2"))
     * @param query Query 右侧表达式
     * @return QueryBinary 二元表达式
     */
    infix fun ge(query: Query): QueryBinary {
        return QueryBinary(this, SqlBinaryOperator.GE, query)
    }

    /**
     * 用于生成Query >= 常量的二元表达式
     * 例如：column("c1") ge 1  或 column("c1").ge(1)
     * @param query T 右侧常量，右侧合法的类型有Number、String、Date、List、Boolean以及null
     * @return QueryBinary 二元表达式
     */
    infix fun <T> ge(query: T): QueryBinary {
        return QueryBinary(this, SqlBinaryOperator.GE, const(query))
    }

    /**
     * 用于生成Query >= 子查询的二元表达式
     * 例如：column("c1") ge (Select() from Table) 或 column("c1").ge(Select() from Table)
     * @param query SelectQuery 子查询
     * @return QueryBinary 二元表达式
     */
    infix fun ge(query: SelectQuery): QueryBinary {
        return QueryBinary(this, SqlBinaryOperator.GE, QuerySub(query))
    }

    /**
     * 用于生成Query < Query的二元表达式
     * 例如：column("c1") lt column("c2") 或 column("c1").lt(column("c2"))
     * @param query Query 右侧表达式
     * @return QueryBinary 二元表达式
     */
    infix fun lt(query: Query): QueryBinary {
        return QueryBinary(this, SqlBinaryOperator.LT, query)
    }

    /**
     * 用于生成Query < 常量的二元表达式
     * 例如：column("c1") lt 1  或 column("c1").lt(1)
     * @param query T 右侧常量，右侧合法的类型有Number、String、Date、List、Boolean以及null
     * @return QueryBinary 二元表达式
     */
    infix fun <T> lt(query: T): QueryBinary {
        return QueryBinary(this, SqlBinaryOperator.LT, const(query))
    }

    /**
     * 用于生成Query < 子查询的二元表达式
     * 例如：column("c1") lt (Select() from Table) 或 column("c1").lt(Select() from Table)
     * @param query SelectQuery 子查询
     * @return QueryBinary 二元表达式
     */
    infix fun lt(query: SelectQuery): QueryBinary {
        return QueryBinary(this, SqlBinaryOperator.LT, QuerySub(query))
    }

    /**
     * 用于生成Query <= Query的二元表达式
     * 例如：column("c1") le column("c2") 或 column("c1").le(column("c2"))
     * @param query Query 右侧表达式
     * @return QueryBinary 二元表达式
     */

    infix fun le(query: Query): QueryBinary {
        return QueryBinary(this, SqlBinaryOperator.LE, query)
    }

    /**
     * 用于生成Query <= 常量的二元表达式
     * 例如：column("c1") le 1  或 column("c1").le(1)
     * @param query T 右侧常量，右侧合法的类型有Number、String、Date、List、Boolean以及null
     * @return QueryBinary 二元表达式
     */
    infix fun <T> le(query: T): QueryBinary {
        return QueryBinary(this, SqlBinaryOperator.LE, const(query))
    }

    /**
     * 用于生成Query <= 子查询的二元表达式
     * 例如：column("c1") le (Select() from Table) 或 column("c1").le(Select() from Table)
     * @param query SelectQuery 子查询
     * @return QueryBinary 二元表达式
     */
    infix fun le(query: SelectQuery): QueryBinary {
        return QueryBinary(this, SqlBinaryOperator.LE, QuerySub(query))
    }

    /**
     * 用于生成IS NULL表达式
     * 例如：column("c1").isNull()
     * @return QueryBinary 二元表达式
     */
    fun isNull(): QueryBinary {
        return QueryBinary(this, SqlBinaryOperator.IS, null)
    }

    /**
     * 用于生成IS NOT NULL表达式
     * 例如：column("c1").isNotNull()
     * @return QueryBinary 二元表达式
     */
    fun isNotNull(): QueryBinary {
        return QueryBinary(this, SqlBinaryOperator.IS_NOT, null)
    }

    /**
     * 用于生成LIKE表达式
     * 例如：column("c1") like "xxx%" 或 column("c1").like("xxx%")
     * @param query String 字符串
     * @return QueryBinary 二元表达式
     */
    infix fun like(query: String): QueryBinary {
        return QueryBinary(this, SqlBinaryOperator.LIKE, const(query))
    }

    /**
     * 用于生成LIKE表达式
     * 例如：column("c1") like concat(const("xxx"), const("%")) 或 column("c1").like(concat(const("xxx"), const("%")))
     * @param query Query 右侧表达式
     * @return QueryBinary 二元表达式
     */
    infix fun like(query: Query): QueryBinary {
        return QueryBinary(this, SqlBinaryOperator.LIKE, query)
    }

    /**
     * 用于生成NOT LIKE表达式
     * 例如：column("c1") notLike "xxx%" 或 column("c1").notLike("xxx%")
     * @param query String 字符串
     * @return QueryBinary 二元表达式
     */
    infix fun notLike(query: String): QueryBinary {
        return QueryBinary(this, SqlBinaryOperator.NOT_LIKE, const(query))
    }

    /**
     * 用于生成NOT LIKE表达式
     * 例如：column("c1") notLike concat(const("xxx"), const("%")) 或 column("c1").notLike(concat(const("xxx"), const("%")))
     * @param query Query 右侧表达式
     * @return QueryBinary 二元表达式
     */
    infix fun notLike(query: Query): QueryBinary {
        return QueryBinary(this, SqlBinaryOperator.NOT_LIKE, query)
    }

    /**
     * 用于生成IN表达式
     * @param query Query 表达式
     * @param list List<T> IN列表
     * @param isNot Boolean 是否为NOT
     * @return QueryInList<T> QueryInList表达式
     */
    private fun <T> inList(query: Query, list: List<T>, isNot: Boolean = false): QueryInList<T> {
        return QueryInList(query, list, isNot)
    }

    /**
     * 用于生成IN子查询表达式
     * @param query Query 表达式
     * @param subQuery SelectQuery 子查询
     * @param isNot Boolean 是否为NOT
     * @return QueryInSubQuery QueryInSubQuery表达式
     */
    private fun inList(query: Query, subQuery: SelectQuery, isNot: Boolean = false): QueryInSubQuery {
        return QueryInSubQuery(query, subQuery, isNot)
    }

    /**
     * 用于生成IN表达式
     * 例如：column("c1") inList listOf(1, 2) 或 column("c1").inList(listOf(1, 2))
     * @param query List<T> IN表达式列表，列表中合法的类型有Number、String、Date、List、Boolean以及null和Query表达式
     * @return QueryInList<T> QueryInList表达式
     */
    infix fun <T> inList(query: List<T>): QueryInList<T> {
        return inList(this, query)
    }

    /**
     * 用于生成NOT IN表达式
     * 例如：column("c1") inList (Select() from Table) 或 column("c1").inList(Select() from Table)
     * @param query SelectQuery 子查询
     * @return QueryInSubQuery QueryInSubQuery表达式
     */
    infix fun inList(query: SelectQuery): QueryInSubQuery {
        return inList(this, query)
    }

    /**
     * 用于生成NOT IN表达式
     * 例如：column("c1") notInList listOf(1, 2) 或 column("c1").notInList(listOf(1, 2))
     * @param query List<T> IN表达式列表，列表中合法的类型有Number、String、Date、List、Boolean以及null和Query表达式
     * @return QueryInList<T> QueryInList表达式
     */
    infix fun <T> notInList(query: List<T>): QueryInList<T> {
        return inList(this, query, true)
    }

    /**
     * 用于生成NOT IN表达式
     * 例如：column("c1") notInList (Select() from Table) 或 column("c1").notInList(Select() from Table)
     * @param query SelectQuery 子查询
     * @return QueryInSubQuery QueryInSubQuery表达式
     */
    infix fun notInList(query: SelectQuery): QueryInSubQuery {
        return inList(this, query, true)
    }

    /**
     * 用于生成AND表达式（每组条件中使用中缀调用时需要注意在条件上添加小括号）
     * 例如：(column("c1") eq 1) and (column("c2") eq 2) 或 (column("c1") eq 1).and(column("c2") eq 2)
     * @param query Query 右侧表达式
     * @return QueryBinary 二元表达式
     */
    infix fun and(query: Query): QueryBinary {
        return QueryBinary(this, SqlBinaryOperator.AND, query)
    }

    /**
     * 用于生成OR表达式（每组条件中使用中缀调用时需要注意在条件上添加小括号）
     * 例如：(column("c1") eq 1) or (column("c2") eq 2) 或 (column("c1") eq 1).or(column("c2") eq 2)
     * @param query Query 右侧表达式
     * @return QueryBinary 二元表达式
     */
    infix fun or(query: Query): QueryBinary {
        return QueryBinary(this, SqlBinaryOperator.OR, query)
    }

    /**
     * 用于生成XOR表达式（每组条件中使用中缀调用时需要注意在条件上添加小括号）
     * 例如：(column("c1") eq 1) xor (column("c2") eq 2) 或 (column("c1") eq 1).xor(column("c2") eq 2)
     * @param query Query 右侧表达式
     * @return QueryBinary 二元表达式
     */
    infix fun xor(query: Query): QueryBinary {
        return QueryBinary(this, SqlBinaryOperator.XOR, query)
    }

    /**
     * 用于生成BETWEEN表达式
     * 例如：column("c1").between(1, 10)
     * @param start T 起始值，合法的类型有Number、String、Date、List、Boolean以及null和Query表达式
     * @param end T 结束值，合法的类型同上
     * @return QueryBetween<T> QueryBetween表达式
     */
    fun <T> between(start: T, end: T): QueryBetween<T> {
        return QueryBetween(this, start, end)
    }

    /**
     * 用于生成NOT BETWEEN表达式
     * 例如：column("c1").notBetween(1, 10)
     * @param start T 起始值，合法的类型有Number、String、Date、List、Boolean以及null和Query表达式
     * @param end T 结束值，合法的类型同上
     * @return QueryBetween<T> QueryBetween表达式
     */
    fun <T> notBetween(start: T, end: T): QueryBetween<T> {
        return QueryBetween(this, start, end, true)
    }

    /**
     * 用于生成json操作符->
     * @param value String 对象名
     * @return QueryJson QueryJson表达式
     */
    infix fun json(value: String): QueryJson {
        return QueryJson(this, SqlBinaryOperator.SUB_GT, value)
    }

    /**
     * 用于生成json操作符->
     * @param value Int 数组下标
     * @return QueryJson QueryJson表达式
     */
    infix fun json(value: Int): QueryJson {
        return QueryJson(this, SqlBinaryOperator.SUB_GT, value)
    }

    /**
     * 用于生成json操作符->>
     * @param value String 对象名
     * @return QueryJson QueryJson表达式
     */
    infix fun jsonText(value: String): QueryJson {
        return QueryJson(this, SqlBinaryOperator.SUB_GT_GT, value)
    }

    /**
     * 用于生成json操作符->>
     * @param value Int 数组下标
     * @return QueryJson QueryJson表达式
     */
    infix fun jsonText(value: Int): QueryJson {
        return QueryJson(this, SqlBinaryOperator.SUB_GT_GT, value)
    }

    /**
     * 对表达式类型起别名
     * 例如：column("c1") alias "xxx" 或 column("c1").alias("xxx")
     * @param alias String 别名
     * @return Query 表达式类型
     */
    open infix fun alias(alias: String): Query {
        this.alias = alias
        return this
    }

    /**
     * 用于生成排序规则ASC
     * 例如：Select() from Table orderBy column("c1").asc()
     * @return OrderBy 排序规则
     */
    fun asc(): OrderBy {
        return OrderBy(this, SqlOrderByOption.ASC)
    }

    /**
     * 用于生成排序规则DESC
     * 例如：Select() from Table orderBy column("c1").desc()
     * @return OrderBy 排序规则
     */
    fun desc(): OrderBy {
        return OrderBy(this, SqlOrderByOption.DESC)
    }
}

/**
 * 查询dsl使用，用于装入ast包的sql语法树中
 * @property expr SqlExpr sql表达式
 * @property alias String? 别名
 */
data class QueryExpr(val expr: SqlExpr, override var alias: String? = null) : Query()

/**
 * 查询dsl使用的字段类型，用于装入ast包的sql语法树中
 * @property column String 字段名
 * @property alias String? 别名
 */
data class QueryColumn(val column: String, override var alias: String? = null) : Query()

/**
 * 查询dsl使用的函数类型，用于装入ast包的sql语法树中
 * @property name String 函数名
 * @property args List<Query> 参数列表
 * @property alias String? 别名
 */
data class QueryExprFunction(val name: String, val args: List<Query>, override var alias: String? = null) : Query()

/**
 * 查询dsl使用的聚合函数类型，用于装入ast包的sql语法树中
 * @property name String 函数名
 * @property args List<Query> 参数列表
 * @property distinct Boolean 是否去重
 * @property attributes Map<String, Query>? 属性列表
 * @property orderBy List<OrderBy> 排序规则列表
 * @property alias String? 别名
 */
data class QueryAggFunction(
    val name: String,
    val args: List<Query>,
    val distinct: Boolean = false,
    val attributes: Map<String, Query>? = null,
    val orderBy: List<OrderBy> = listOf(),
    override var alias: String? = null
) : Query() {
    /**
     * 用于生成窗口函数
     * 例如：count().over()
     * @return QueryOver 窗口函数表达式
     */
    fun over(): QueryOver {
        return QueryOver(this, listOf(), listOf())
    }
}

/**
 * 查询dsl使用的常量类型，用于装入ast包的sql语法树中
 * @property value T 合法的类型有Number、String、Date、List、Boolean以及null
 * @property alias String? 别名
 */
data class QueryConst<T>(val value: T, override var alias: String? = null) : Query()

/**
 * 查询dsl使用的二元运算类型，用于装入ast包的sql语法树中
 * @property left Query 二元运算符左侧表达式
 * @property operator SqlBinaryOperator 二元运算符
 * @property right Query? 二元运算符右侧表达式
 * @property alias String? 别名
 */
data class QueryBinary(
    val left: Query,
    val operator: SqlBinaryOperator,
    val right: Query?,
    override var alias: String? = null
) :
    Query() {
    /**
     * 用于生成CASE WHEN匹配分支
     * 例如：column("c1") eq "xxx" then 1
     * @param then T 合法的类型有Number、String、Date、List、Boolean以及null和Query表达式类型
     * @return CaseBranch<T> CASE WHEN匹配分支
     */
    infix fun <T> then(then: T): CaseBranch<T> {
        return CaseBranch(this, then)
    }
}

/**
 * 查询dsl使用的子查询类型，用于装入ast包的sql语法树中
 * @property selectQuery SelectQuery 子查询
 * @property alias String? 别名
 */
data class QuerySub(val selectQuery: SelectQuery, override var alias: String? = null) : Query()

/**
 * 查询dsl使用的CASE WHEN表达式类型，用于装入ast包的sql语法树中
 * @property conditions List<CaseBranch<T>> 匹配分支列表
 * @property default T? 默认值
 * @property alias String? 别名
 */
data class QueryCase<T>(
    val conditions: List<CaseBranch<T>>,
    val default: T? = null,
    override var alias: String? = null
) : Query() {
    /**
     * 用于生成CASE WHEN表达式
     * @param value T? 默认值，合法的类型有Number、String、Date、List、Boolean以及null和Query表达式类型
     * @return QueryCase<T> CASE WHEN表达式
     */
    infix fun elseIs(value: T?): QueryCase<T> {
        return if (value != null) {
            QueryCase(this.conditions, value)
        } else {
            this
        }
    }
}

/**
 * 实体类的伴生对象中使用的字段类型，用于装入ast包的sql语法树中
 * @property table String 表名
 * @property column String 字段名
 * @property incr Boolean 是否自增
 * @property primaryKey Boolean 是否是主键
 * @property alias String? 别名
 */
data class QueryTableColumn(
    val table: String,
    val column: String,
    var incr: Boolean = false,
    var primaryKey: Boolean = false,
    var autoGenerateKey: Boolean = false,
    var generateFunction: () -> Any = {},
    override var alias: String? = null
) : Query() {
    /**
     * 设置字段为自增字段
     * @return QueryTableColumn 字段类型表达式
     */
    fun incr(): QueryTableColumn {
        this.incr = true
        return this
    }

    /**
     * 设置字段为自动生成主键
     * @return QueryTableColumn 字段类型表达式
     */
    fun autoGenerateKey(): QueryTableColumn {
        this.autoGenerateKey = true
        return this
    }

    /**
     * 设置主键生成策略
     * @param function Function0<Any> 生成策略
     * @return QueryTableColumn 字段类型表达式
     */
    fun generateFunction(function: () -> Any): QueryTableColumn {
        this.generateFunction = function
        return this
    }

    /**
     * 设置字段为主键
     * @return QueryTableColumn 字段类型表达式
     */
    fun primaryKey(): QueryTableColumn {
        this.primaryKey = true
        return this
    }

    override fun alias(alias: String): QueryTableColumn = this.copy(alias = alias)
}

/**
 * 查询dsl使用的Json操作，用于装入ast包的sql语法树中
 * @property query Query 左侧表达式
 * @property operator SqlBinaryOperator 运算符
 * @property value Any 对象名或数组下标
 * @property alias String? 别名
 */
data class QueryJson(
    val query: Query,
    val operator: SqlBinaryOperator,
    val value: Any,
    override var alias: String? = null
) : Query()

/**
 * 查询dsl使用的CAST表达式，用于装入ast包的sql语法树中
 * @property query Query 待转换表达式
 * @property type String 转换的类型
 * @property alias String? 别名
 */
data class QueryCast(val query: Query, val type: String, override var alias: String? = null) : Query()

/**
 * 查询dsl使用的IN表达式，用于装入ast包的sql语法树中
 * @property query Query 左侧表达式
 * @property list List<T> IN表达式列表，列表中合法的类型有Number、String、Date、List、Boolean以及null和Query表达式
 * @property isNot Boolean 是否为NOT
 * @property alias String? 别名
 */
data class QueryInList<T>(
    val query: Query,
    val list: List<T>,
    val isNot: Boolean = false,
    override var alias: String? = null
) : Query()

/**
 * 查询dsl使用的IN子查询表达式，用于装入ast包的sql语法树中
 * @property query Query 左侧表达式
 * @property subQuery SelectQuery IN子查询
 * @property isNot Boolean 是否为NOT
 * @property alias String? 别名
 */
data class QueryInSubQuery(
    val query: Query,
    val subQuery: SelectQuery,
    val isNot: Boolean = false,
    override var alias: String? = null
) : Query()

/**
 * 查询dsl使用的BETWEEN子查询表达式，用于装入ast包的sql语法树中
 * @property query Query 左侧表达式
 * @property start T 起始值，合法的类型有Number、String、Date、List、Boolean以及null和Query表达式
 * @property end T 结束值，合法类型同上
 * @property isNot Boolean 是否为NOT
 * @property alias String? 别名
 */
data class QueryBetween<T>(
    val query: Query,
    val start: T,
    val end: T,
    val isNot: Boolean = false,
    override var alias: String? = null
) : Query()

/**
 * 查询dsl使用的通配符，用于装入ast包的sql语法树中
 * @property owner String? 表名
 * @property alias String? 别名
 */
data class QueryAllColumn(val owner: String? = null, override var alias: String? = null) : Query()

/**
 * 查询dsl使用的窗口函数类型，用于装入ast包的sql语法树中
 * @property function QueryAggFunction 创建窗口函数的聚合函数
 * @property partitionBy List<Query> 窗口分组列表
 * @property orderBy List<OrderBy> 排序规则列表
 * @property alias String? 别名
 */
data class QueryOver(
    val function: QueryAggFunction,
    val partitionBy: List<Query> = listOf(),
    val orderBy: List<OrderBy> = listOf(),
    override var alias: String? = null
) : Query() {
    /**
     * 窗口函数分组
     * @param query Array<out Query> 分组表达式列表
     * @return QueryOver 窗口函数表达式
     */
    fun partitionBy(vararg query: Query): QueryOver {
        return QueryOver(this.function, this.partitionBy + query, this.orderBy)
    }

    /**
     * 窗口函数分组
     * @param query Query 分组表达式
     * @return QueryOver 窗口函数表达式
     */
    infix fun partitionBy(query: Query): QueryOver {
        return QueryOver(this.function, this.partitionBy + query, this.orderBy)
    }

    /**
     * 窗口函数分组
     * @param query List<Query> 分组表达式列表
     * @return QueryOver 窗口函数表达式
     */
    infix fun partitionBy(query: List<Query>): QueryOver {
        return QueryOver(this.function, this.partitionBy + query, this.orderBy)
    }

    /**
     * 窗口函数排序正序
     * @param order Array<out Query> 排序表达式列表
     * @return QueryOver 窗口函数表达式
     */
    fun orderByAsc(vararg order: Query): QueryOver {
        val orderBy = order.map { OrderBy(it, SqlOrderByOption.ASC) }
        return QueryOver(this.function, this.partitionBy, this.orderBy + orderBy)
    }

    /**
     * 窗口函数排序倒序
     * @param order Array<out Query> 排序表达式列表
     * @return QueryOver 窗口函数表达式
     */
    fun orderByDesc(vararg order: Query): QueryOver {
        val orderBy = order.map { OrderBy(it, SqlOrderByOption.DESC) }
        return QueryOver(this.function, this.partitionBy, this.orderBy + orderBy)
    }

    /**
     * 窗口函数排序正序
     * @param order Query 排序表达式
     * @return QueryOver 窗口函数表达式
     */
    infix fun orderByAsc(order: Query): QueryOver {
        return QueryOver(this.function, this.partitionBy, this.orderBy + OrderBy(order, SqlOrderByOption.ASC))
    }

    /**
     * 窗口函数排序倒序
     * @param order Query 排序表达式
     * @return QueryOver 窗口函数表达式
     */
    infix fun orderByDesc(order: Query): QueryOver {
        return QueryOver(this.function, this.partitionBy, this.orderBy + OrderBy(order, SqlOrderByOption.DESC))
    }

    /**
     * 窗口函数排序正序
     * @param order List<Query> 排序表达式列表
     * @return QueryOver 窗口函数表达式
     */
    infix fun orderByAsc(order: List<Query>): QueryOver {
        val orderBy = order.map { OrderBy(it, SqlOrderByOption.ASC) }
        return QueryOver(this.function, this.partitionBy, this.orderBy + orderBy)
    }

    /**
     * 窗口函数排序倒序
     * @param order List<Query> 排序表达式列表
     * @return QueryOver 窗口函数表达式
     */
    infix fun orderByDesc(order: List<Query>): QueryOver {
        val orderBy = order.map { OrderBy(it, SqlOrderByOption.DESC) }
        return QueryOver(this.function, this.partitionBy, this.orderBy + orderBy)
    }

    /**
     * 窗口函数排序
     * @param order Array<out OrderBy> 排序规则列表（使用表达式类型的.asc()或.desc()生成）
     * @return QueryOver 窗口函数表达式
     */
    fun orderBy(vararg order: OrderBy): QueryOver {
        val orderByList = order.toList()
        return QueryOver(this.function, this.partitionBy, this.orderBy + orderByList)
    }

    /**
     * 窗口函数排序
     * @param order OrderBy 排序规则（使用表达式类型的.asc()或.desc()生成）
     * @return QueryOver 窗口函数表达式
     */
    infix fun orderBy(order: OrderBy): QueryOver {
        return QueryOver(this.function, this.partitionBy, this.orderBy + order)
    }

    /**
     * 窗口函数排序
     * @param order List<OrderBy> 排序规则列表（使用表达式类型的.asc()或.desc()生成）
     * @return QueryOver 窗口函数表达式
     */
    infix fun orderBy(order: List<OrderBy>): QueryOver {
        return QueryOver(this.function, this.partitionBy, this.orderBy + order)
    }
}

/**
 * 查询dsl使用的子查询谓词表达式，用于装入ast包的sql语法树中
 * @property query SelectQuery 子查询
 * @property predicate SqlSubQueryPredicate 子查询谓词
 * @property alias String? 别名
 */
data class QuerySubQueryPredicate(
    val query: SelectQuery,
    val predicate: SqlSubQueryPredicate,
    override var alias: String? = null
) : Query()

/**
 * CASE WHEN匹配分支
 * @property query Query 匹配表达式
 * @property then T 匹配到时选择的值，合法的类型有Number、String、Date、List、Boolean以及null和Query表达式
 */
data class CaseBranch<T>(val query: Query, val then: T)

/**
 * 排序规则
 * @property query Query 表达式
 * @property order SqlOrderByOption 排序规则枚举
 */
data class OrderBy(val query: Query, val order: SqlOrderByOption)